#!/usr/bin/env python
# encoding: utf-8

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

from ui.oar import Ui_Dialog as oarDialog
from win32api import GetSystemMetrics

from RayGraphWidget import RayCanvasWidget
from graphRoad import drawWidget
from common.widgets.charts.RoadChartView import RoadChartView
import re
import os


class OarDialog(QDialog, oarDialog):
    def __init__(self,parent=None):
        super(QDialog, self).__init__(parent)
        self.setupUi(self)

        self.pos = [0,10,20,30]
        self.step = [5,1,2]
        self.angle = 0

        #  窗口尺寸设计
        w = GetSystemMetrics (0)/1.2
        h = GetSystemMetrics (1)/1.2
        self.setFixedSize(w,h)
        # 确认 取消
        self.btn_ok.clicked.connect(self.accept)
        self.btn_cancel.clicked.connect(self.reject)

        self.pushButton_modify.clicked.connect(self.modifyPosStep)
        # 设置目标和步距
        self.listView = QListWidget()
        self.listView.clicked.connect(self.listView_Clicked)
        self.verticalLayout_list.addWidget(self.listView)
        #  路线变化示意图
        #  self.drawW = drawWidget()
        #  self.drawW.setFixedSize(w*1.5/3, h*1/3)
        #  self.drawW.pdd_oar_ray = 'oar'
        # self.verticalLayout_list.addWidget(self.drawW)

        #  路线变化示意图
        self.roadChartView = RoadChartView()
        self.verticalLayout_list.addWidget(self.roadChartView)

        # 射线照射3d示意图
        self.rayCanvasWidget = RayCanvasWidget()
        self.verticalLayout_chart.addWidget(self.rayCanvasWidget)
        # 设置编辑框只能输入数字
        self.doubleSpinBox_target.setEnabled(False)

        self.comboBox_direction.currentIndexChanged.connect(self.updateValue)
        self.comboBox_rayType.currentIndexChanged.connect(self.updateValue)
        self.doubleSpinBox_ssd.valueChanged.connect(self.updateValue)
        self.doubleSpinBox_deepth.valueChanged.connect(self.updateValue)
        self.doubleSpinBox_edge.valueChanged.connect(self.updateValue)
        self.spinBox_raysize_x.valueChanged.connect(self.updateValue)
        self.spinBox_raysize_y.valueChanged.connect(self.updateValue)
        self.spinBox_power.valueChanged.connect(self.updateValue)

        self.radioButton_1.clicked.connect(self.updateValue)
        self.radioButton_2.clicked.connect(self.updateValue)
        self.radioButton_3.clicked.connect(self.updateValue)
        self.radioButton_4.clicked.connect(self.updateValue)

        self.checkBox_left.clicked.connect(self.updateValue)
        self.checkBox_right.clicked.connect(self.updateValue)

        # self.styleChaned()

        self.updateValue()

    def styleChaned(self):
        pixmap = None
        if self.radioButton_1.isChecked():
            self.angle = 0
            pixmap = QPixmap(r"%s/images/xyz-0.png"%os.getcwd())
        if self.radioButton_2.isChecked():
            self.angle = 90
            pixmap = QPixmap(r"%s/images/xyz-90.png"%os.getcwd())
        if self.radioButton_3.isChecked():
            self.angle = 180
            pixmap = QPixmap(r"%s/images/xyz-180.png"%os.getcwd())
        if self.radioButton_4.isChecked():
            self.angle = 270
            pixmap = QPixmap(r"%s/images/xyz-270.png"%os.getcwd())
        pixmap.scaled(self.label_style.size(), Qt.KeepAspectRatio)
        self.label_style.setScaledContents(True)
        self.label_style.setPixmap(pixmap)

    def styleSet(self, angle):
        if angle == '01':
            self.radioButton_1.setChecked(True)
        if angle == '02':
            self.radioButton_2.setChecked(True)
        if angle == '03':
            self.radioButton_3.setChecked(True)
        if angle == '04':
            self.radioButton_4.setChecked(True)

    def raytype_changed(self):
        """射线类型变化，能量单位跟着变化"""
        if self.comboBox_rayType.currentText() == "电子":
            self.label_power.setText("能量(MeV)")
        if self.comboBox_rayType.currentText() == "光子":
            self.label_power.setText("能量(MV)")

    def modifyPosStep(self):
        """修改位置"""
        pos = self.doubleSpinBox_target.value()
        step = self.doubleSpinBox_step.value()
        if pos and step:
            index = None
            for i in range(0,len(self.pos)):
                if pos == self.pos[i]:
                    index = i
                    break
            if index is not None:
                before_pos = self.pos[index-1]
                after_pos = self.pos[index]
                max_inv = after_pos - before_pos
                if step <= max_inv:
                    self.step[index-1] = step
                else:
                    QMessageBox.warning(self, '警告', '步距设置错误,超出范围,无法修改！！！', QMessageBox.Yes)
                    return
                self.updateValue()
        else:
            QMessageBox.warning(self, '提示', '请从下面选择要修改的路段', QMessageBox.Yes)

    def is_number(self, num):
        """判断是否为数字，正值、小数、整数, 不包含负数"""
        pattern = re.compile(r'^[0-9]+([.]{1}[0-9]+){0,1}$')
        result = pattern.match(num)
        if result:
            return True
        else:
            return False

    def check_args(self):
        ssd       = self.lineEdit_SSD.text()
        if not ssd:
            QMessageBox.warning(self, '警告',"源皮距设置错误",QMessageBox.Yes)
            return False
        raySize_x = self.lineEdit_raysize_x.text()
        if not raySize_x:
            QMessageBox.warning(self, '警告',"射野x设置错误",QMessageBox.Yes)
            return False
        raySize_y = self.lineEdit_raysize_y.text()
        if not raySize_y:
            QMessageBox.warning(self, '警告',"射野y设置错误",QMessageBox.Yes)
            return False
        deepth    = self.lineEdit_deepth.text()
        if not deepth:
            QMessageBox.warning(self, '警告',"测量深度设置错误",QMessageBox.Yes)
            return False
        return True

    def updateValue(self):
        """更新各个参数，用在每个参数变化的时候都调用此函数"""
        # raysize_x = self.lineEdit_raysize_x.text()
        # raysize_y = self.lineEdit_raysize_y.text()
        # ssd = self.lineEdit_SSD.text()
        # deepth = self.lineEdit_deepth.text()
        # edge = self.comboBox_edge.currentText()

        self.raysize_x = self.spinBox_raysize_x.value()
        self.raysize_y = self.spinBox_raysize_y.value()
        self.ssd = self.doubleSpinBox_ssd.value()
        self.deepth = self.doubleSpinBox_deepth.value()
        self.direction = self.comboBox_direction.currentText()
        self.raytype= self.comboBox_rayType.currentText()
        self.power = self.spinBox_power.value()
        self.edge = self.doubleSpinBox_edge.value()

        if self.edge > self.raysize_x * 10:
            self.doubleSpinBox_edge.setValue(0)
        if self.raytype == "电子":
            self.label_power.setText("能量(MeV)")
        if self.raytype == "光子":
            self.label_power.setText("能量(MV)")
        # 更新位置
        self.updatePosStep()
        self.listView_UpdateRoad()
        # 更新位置步距后计算路径
        self.road = self.getRoad()
        # 更新角度
        self.styleChaned()
        # 算出路径后更新射野显示
        self.edge_x=max(self.pos_x)-self.raysize_x*10/2
        self.edge_y=max(self.pos_y)-self.raysize_y*10/2

        # 左右半边测量方案，用于测量大射野
        self.half = ''
        length = len(self.road)
        if self.checkBox_left.isChecked() and not self.checkBox_right.isChecked():
            self.half = 'left'
            if length % 2 == 0:
                self.road = self.road[:int(length/2)]
            else:
                self.road = self.road[:int(length/2)+1]
        if self.checkBox_right.isChecked() and not self.checkBox_left.isChecked():
            self.half = 'right'
            if length % 2 == 0:
                self.road = self.road[int(length/2):]
            else:
                self.road = self.road[int(length/2)+1:]
        # 更新路径示意图
        self.roadChartView.updateOarRoad(self.step, self.pos, self.road, self.direction, self.half, self.angle)
        self.rayCanvasWidget.updateItems(
                                        angle=self.angle,
                                        ssd=-self.ssd,
                                        raySize_x=self.raysize_x,
                                        raySize_y=self.raysize_y,
                                        raySizeEdge_x=self.edge_x,
                                        raySizeEdge_y=self.edge_y,
                                        deepth=self.deepth,
                                        road=self.road)

    def updatePosStep(self):
        """更新位置和布局，根据射野的比例动态变化"""
        raysize_x = float(self.raysize_x) * 10
        raysize_y = float(self.raysize_y) * 10
        edge = self.edge
        self.pos=[0,int(raysize_x/2-edge/2),int(raysize_x/2+edge/2),raysize_x/2+edge]
        pos_x = self.pos
        step_x = self.step
        per = raysize_y/raysize_x
        pos_y = [p*per for p in pos_x]
        step_y = [p*per for p in step_x]
        self.pos = pos_x
        self.step = step_x

        self.pos_x = pos_x
        self.step_x = step_x

        self.pos_y = pos_y
        self.step_y = step_y

    def listView_UpdateRoad(self):
        '''重置任务显示列表,并更新示意图显示'''
        pos = self.pos
        step = self.step
        self.listView.clear()
        for i in range(1,len(pos)):
            text = '%.1f mm -> %.1fmm step:%.1f'%(pos[i-1],pos[i],step[i-1])
            self.listView.addItem(text)

    def listView_Clicked(self,index):
        self.listView_currentItem= self.listView.currentItem()
        t = self.listView.currentItem().text()
        target = t.split(' ')[3][:-2]
        step = t.split(' ')[4][5:]
        self.doubleSpinBox_target.setValue(float(target))
        self.doubleSpinBox_step.setValue(float(step))

    def getRoad_bk(self):
        '''获取路线'''
        deepth = self.lineEdit_deepth.text()
        direction = self.comboBox_direction.currentText()
        Road = []
        end = len(self.pos)
        for i in range(1,end):
            if direction=='B->A':
                if i==1:
                    Road.append([self.pos_x[end-i],0,int(deepth),0,0,0])
                    Road.insert(i,[-self.pos_x[end-i],0,int(deepth),self.step_x[end-i-1],0,0])
                else:
                    Road.insert(i-1,[self.pos_x[end-i],0,int(deepth),self.step_x[end-i],0,0])
                    Road.insert(i,[-self.pos_x[end-i],0,int(deepth),self.step_x[end-i-1],0,0])
            if direction=='A->B':
                if i==1:
                    Road.append([-self.pos_x[end-i],0,int(deepth),0,0,0])
                    Road.insert(i,[self.pos_x[end-i],0,int(deepth),self.step_x[end-i-1],0,0])
                else:
                    Road.insert(i-1,[-self.pos_x[end-i],0,int(deepth),self.step_x[end-i],0,0])
                    Road.insert(i,[self.pos_x[end-i],0,int(deepth),self.step_x[end-i-1],0,0])
            if direction=='G->T':
                if i==1:
                    Road.append([0,-self.pos_y[end-i],int(deepth),0,0,0])
                    Road.insert(i,[0,self.pos_y[end-i],int(deepth),0,self.step_y[end-i-1],0])
                else:
                    Road.insert(i-1,[0,-self.pos_y[end-i],int(deepth),0,self.step_y[end-i],0])
                    Road.insert(i,[0,self.pos_y[end-i],int(deepth),0,self.step_y[end-i-1],0])
            if direction=='T->G':
                if i==1:
                    Road.append([0,self.pos_y[end-i],int(deepth),0,0,0])
                    Road.insert(i,[0,-self.pos_y[end-i],int(deepth),0,self.step_y[end-i-1],0])
                else:
                    Road.insert(i-1,[0,self.pos_y[end-i],int(deepth),0,self.step_y[end-i],0])
                    Road.insert(i,[0,-self.pos_y[end-i],int(deepth),0,self.step_y[end-i-1],0])
            if direction=='BT->AG':
                if i==1:
                    Road.append([self.pos_x[end-i],self.pos_y[end-i],int(deepth),0,0,0])
                    Road.insert(i,[-self.pos_x[end-i],-self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
                else:
                    Road.insert(i-1,[self.pos_x[end-i],self.pos_y[end-i],int(deepth),self.step_x[end-i],self.step_y[end-i],0])
                    Road.insert(i,[-self.pos_x[end-i],-self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
            if direction=='AG->BT':
                if i==1:
                    Road.append([-self.pos_x[end-i],-self.pos_y[end-i],int(deepth),0,0,0])
                    Road.insert(i,[self.pos_x[end-i],self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
                else:
                    Road.insert(i-1,[-self.pos_x[end-i],-self.pos_y[end-i],int(deepth),self.step_x[end-i],self.step_y[end-i],0])
                    Road.insert(i,[self.pos_x[end-i],self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
            if direction=='BG->AT':
                if i==1:
                    Road.append([self.pos_x[end-i],-self.pos_y[end-i],int(deepth),0,0,0])
                    Road.insert(i,[-self.pos_x[end-i],self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
                else:
                    Road.insert(i-1,[self.pos_x[end-i],-self.pos_y[end-i],int(deepth),self.step_x[end-i],self.step_y[end-i],0])
                    Road.insert(i,[-self.pos_x[end-i],self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
            if direction=='AT->BG':
                if i==1:
                    Road.append([-self.pos_x[end-i],self.pos_y[end-i],int(deepth),0,0,0])
                    Road.insert(i,[self.pos_x[end-i],-self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
                else:
                    Road.insert(i-1,[-self.pos_x[end-i],self.pos_y[end-i],int(deepth),self.step_x[end-i],self.step_y[end-i],0])
                    Road.insert(i,[self.pos_x[end-i],-self.pos_y[end-i],int(deepth),self.step_x[end-i-1],self.step_y[end-i-1],0])
        Road.append([0,0,0,0,0,0])
        return Road

    def getRoad(self):
        '''获取路线'''
        deepth = self.doubleSpinBox_deepth.value()
        direction = self.comboBox_direction.currentText()
        Road = []
        end = len(self.pos)
        def return_axis(pos,step):
            axis = []
            for i in range(1,len(pos)):
                err = abs(pos[i]-pos[i-1])
                s = step[i-1]
                p = pos[i-1]
                if s==0:
                    return
                for j in range(0,abs(int(err/s))+1):
                    axis.append(p+j*s)
                axis.append(pos[i])
            # 去重复，正序排列
            set_axis = list(set(axis))
            # 合并
            axis = set_axis + [-a for a in set_axis if a>0]
            # 去重复，正序排列
            # sort_axis = sorted(list(set(axis)))
            return sorted(axis)
        road = []
        axis_x = return_axis(self.pos_x, self.step_x)
        axis_x = [float('%.1f'%a) for a in axis_x]
        axis_y = return_axis(self.pos_y, self.step_y)
        axis_y = [float('%.1f'%a) for a in axis_y]
        if direction=='A->B':
            road = [[x,0,deepth] for x in axis_x]
        if direction=='B->A':
            road = [[-x,0,deepth] for x in axis_x]
        if direction=='G->T':
            road = [[0,y,deepth] for y in axis_y]
        if direction=='T->G':
            road = [[0,-y,deepth] for y in axis_y]
        if direction=='BT->AG':
            road = [[-x,-y,deepth] for x,y in zip(axis_x,axis_y)]
        if direction=='AG->BT':
            road = [[x,y,deepth] for x,y in zip(axis_x,axis_y)]
        if direction=='AT->BG':
            road = [[x,-y,deepth] for x,y in zip(axis_x,axis_y)]
        if direction=='BG->AT':
            road = [[-x,y,deepth] for x,y in zip(axis_x,axis_y)]
        # 坐标系转换到加速器
        if self.radioButton_1.isChecked():
            road = [[r[0],r[1],r[2]] for r in road]
        if self.radioButton_2.isChecked():
            road = [[r[1],-r[0],r[2]] for r in road]
        if self.radioButton_3.isChecked():
            road = [[-r[0],-r[1],r[2]] for r in road]
        if self.radioButton_4.isChecked():
            road = [[-r[1],r[0],r[2]] for r in road]
        return road

    def load_config(self, conf):
        self.doubleSpinBox_deepth.setValue(float(conf['deepth'].replace('mm','')))
        self.doubleSpinBox_ssd.setValue(float(conf['ssd'].replace('cm','')))
        self.spinBox_raysize_x.setValue(float(conf['ray_size_x'].replace('cm','')))
        self.spinBox_raysize_y.setValue(float(conf['ray_size_y'].replace('cm','')))
        self.spinBox_power.setValue(int(conf['power'].replace('MeV','').replace('MV','')))
        self.doubleSpinBox_edge.setValue(float(conf['ray_size_edge_x'].replace('mm','')))
        for i in range(0,self.comboBox_rayType.count()):
            if self.comboBox_rayType.itemText(i) == conf['ray_type']:
                self.comboBox_rayType.setCurrentIndex(i)
                break
        for i in range(0,self.comboBox_direction.count()):
            if self.comboBox_direction.itemText(i) == conf['direction']:
                self.comboBox_direction.setCurrentIndex(i)
                break
        angle = conf['angle'] if 'angle' in conf else ''
        if angle =='0':
            self.radioButton_1.setChecked(True)
        if angle =='90':
            self.radioButton_2.setChecked(True)
        if angle =='180':
            self.radioButton_3.setChecked(True)
        if angle =='270':
            self.radioButton_4.setChecked(True)

        half = conf['half'] if 'half' in conf else ''
        self.checkBox_left.setChecked(False)
        self.checkBox_right.setChecked(False)
        if half =='left':
            self.checkBox_left.setChecked(True)
            self.checkBox_right.setChecked(False)
        if half =='right':
            self.checkBox_left.setChecked(False)
            self.checkBox_right.setChecked(True)
        self.step_x = conf['step_x']
        self.step_y = conf['step_y']
        self.pos_x = conf['pos_x']
        self.pos_y = conf['pos_y']
        self.step = conf['step_x']
        self.pos = conf['pos_x']
        self.updateValue()

    def accept(self):
        self.conf = {
            'type':'OAR',
            'road':self.road,
            'deepth':str(self.deepth)+'mm',
            'ray_type':self.raytype,
            'power':self.power,
            'ssd':str(self.ssd)+'cm',
            'ray_size_x':str(self.raysize_x)+'cm',
            'ray_size_y':str(self.raysize_y)+'cm',
            'ray_size_edge_x':str(self.edge_x)+'mm',
            'ray_size_edge_y':str(self.edge_y)+'mm',
            'step_x':self.step_x,
            'step_y':self.step_y,
            'pos_x':self.pos_x,
            'pos_y':self.pos_y,
            'direction':self.direction,
            'half':self.half,
            'angle':self.angle,
        }
        QDialog.accept(self)

    def reject(self):
        QDialog.reject(self)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    win = OarDialog()
    win.show()
    app.exec_()

